package com.soriya.nestlive.viewmodel

import android.app.Application
import android.content.Context
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import com.soriya.nestlive.application.MyApplication
import com.soriya.nestlive.constant.CommonConstant
import com.soriya.nestlive.db.dao.ChannelInfoDao
import com.soriya.nestlive.db.dao.UserInfoDao
import com.soriya.nestlive.db.entity.ChannelInfoEntity
import com.soriya.nestlive.model.Channel
import com.soriya.nestlive.model.PageResult
import com.soriya.nestlive.model.ResponseResult
import com.soriya.nestlive.model.form.CreateChannelForm
import com.soriya.nestlive.net.UploadApi
import com.soriya.nestlive.repository.ChannelRecommendPagingRepository
import com.soriya.nestlive.repository.ChannelRepository
import com.soriya.nestlive.repository.ChannelSearchPagingRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import javax.inject.Inject

@HiltViewModel
class ChannelModel @Inject constructor(
    private val channelRepository: ChannelRepository,
    private val uploadApi: UploadApi,
    private val userInfoDao: UserInfoDao,
    private val channelInfoDao: ChannelInfoDao,
    private val channelRecommendPagingRepository: ChannelRecommendPagingRepository,
    private val channelSearchPagingRepository: ChannelSearchPagingRepository,
    application: Application
) : AndroidViewModel(application) {

    private val _channelList = MutableStateFlow(listOf<Channel>())

    val channelList: StateFlow<List<Channel>> = _channelList

    private val _channelDetail = MutableStateFlow<Channel?>(null)
    val channelDetail: StateFlow<Channel?> = _channelDetail

    // 分页数据
    val recommendChannelList = Pager(
        PagingConfig(
            pageSize = 5, // 页面大小
            prefetchDistance = 2, // 距离底部还有多少条数据加载下一页
            enablePlaceholders = false, // 控件占位 false不占位
            initialLoadSize = 5 // 初始化时加载多少条数据
        )
    ) {
        channelRecommendPagingRepository
    }.flow

    fun search(key: String) = Pager(
        PagingConfig(
            pageSize = 5, // 页面大小
            prefetchDistance = 2, // 距离底部还有多少条数据加载下一页
            enablePlaceholders = false, // 控件占位 false不占位
            initialLoadSize = 5 // 初始化时加载多少条数据
        )
    ) {
        channelSearchPagingRepository.key = key
        channelSearchPagingRepository
    }.flow

    init {
        viewModelScope.launch {

            val sharedPreferences = getApplication<MyApplication>().getSharedPreferences(
                CommonConstant.USER_INFO_KEY,
                Context.MODE_PRIVATE
            )

            val token = sharedPreferences.getString("token", null)

            if (token != null) {
                userInfoDao.selectOne().collect { info ->
                    if (info != null) {
                        channelRepository.getFollowedChannelList(userId = info.userId).collect { res ->
                            when (res) {
                                is ResponseResult.Success<*> -> {
                                    val pageResult = res.data as PageResult<*>
                                    _channelList.emit(pageResult.list.map {
                                        it as Channel
                                    })
                                }
                                is ResponseResult.Failed -> {
                                    _channelList.emit(listOf())
                                }
                                is ResponseResult.Loading -> {
                                    _channelList.emit(listOf())
                                }
                            }
                        }
                    }
                }
            } else {
                // 未登录，推荐
            }
        }
    }

    fun getMyChannel(cache: Boolean = true) = viewModelScope.launch {
        val channelInfo = channelInfoDao.selectOne().first()

        if (cache && channelInfo != null && channelInfo.updateTime > System.currentTimeMillis() - 1000 * 60 * 30) {
            _channelDetail.emit(channelInfo.run {
                Channel(
                    id = channelId,
                    userId = userId,
                    channelName = channelName,
                    backgroundCover = backgroundCover,
                    about = about,
                    follows = follows,
                    liveState = liveState,
                    nickname = nickname,
                    avatar = avatar
                )
            })
            return@launch
        }

        channelRepository.getMyChannel().collect { res ->
            when (res) {
                is ResponseResult.Success<*> -> {
                    val channel = res.data as Channel?

                    _channelDetail.emit(channel)

                    channel?.run {
                        val channelInfoEntity = ChannelInfoEntity(
                            _id = 1,
                            channelId = id!!,
                            userId = userId,
                            channelName = channelName,
                            backgroundCover = backgroundCover,
                            about = about,
                            follows = follows,
                            liveState = liveState,
                            nickname = nickname,
                            avatar = avatar,
                            updateTime = System.currentTimeMillis()
                        )

                        viewModelScope.launch(Dispatchers.IO) {
                            channelInfoDao.insert(channelInfoEntity)
                        }

                        channelInfoEntity
                    }
                }
                is ResponseResult.Failed -> {
                    Log.e("SoRiya", "MyChannel请求失败")
                    _channelDetail.emit(null)
                }
                is ResponseResult.Loading -> {
                    _channelDetail.emit(Channel.EMPTY)
                }
            }
        }
    }

    fun createChannel(createChannelForm: CreateChannelForm): Flow<Unit?> = flow {
        val backgroundCover = createChannelForm.backgroundCover
        val requestBody = backgroundCover.asRequestBody("multipart/form-data".toMediaTypeOrNull())

        val createFormData =
            MultipartBody.Part.createFormData("file", backgroundCover.name, requestBody)

        val coverPath = uploadApi.updateImage(createFormData)

        if (coverPath.code != 200) {
            Log.i("SoRiya", "图片上传失败!")
            return@flow
        }

        channelRepository.createChannel(
            Channel(
                backgroundCover = coverPath.data,
                channelName = createChannelForm.channelName,
                about = createChannelForm.about
            )
        ).collect { res ->
            when (res) {
                is ResponseResult.Success<*> -> {
                    if (res.code == 200) {
                        emit(Unit)
                    }
                }
                is ResponseResult.Failed -> {}
                is ResponseResult.Loading -> {}
            }
        }
    }

    fun getDetailById(id: Long) = viewModelScope.launch {
        channelRepository.getById(id).collect { res ->
            when (res) {
                is ResponseResult.Success<*> -> {
                    if (res.code == 200) {
                        _channelDetail.emit(res.data as Channel)
                    }
                }
                is ResponseResult.Failed -> {}
                is ResponseResult.Loading -> {}
            }
        }
    }

    fun follow(id: Long): Flow<Unit?> = flow {
        channelRepository.follow(id).collect { res ->
            when (res) {
                is ResponseResult.Success<*> -> {
                    if (res.code == 200) {
                        emit(Unit)
                    }
                }
                is ResponseResult.Failed -> {}
                is ResponseResult.Loading -> {}
            }
        }
    }

    fun clean() {
        channelInfoDao.clear()
    }

}